package com.sky.config;

import com.sky.interceptor.JwtTokenAdminInterceptor;
import com.sky.interceptor.JwtTokenUserInterceptor;
import com.sky.json.JacksonObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.List;

/**
 * 配置类，注册web层相关组件
 */
@Configuration
@Slf4j
@RequiredArgsConstructor
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
    /**
     * 要实现自定义配置 Web MVC 的功能，有两种常见的方式
     * 1.实现 WebMvcConfigurer 接口：
     * 常见的方法包括添加拦截器、静态资源处理、跨域配置等。同时也能保留对 Spring MVC 默认配置的部分继承。
     * 2.继承 WebMvcConfigurationSupport 类：
     * 使用 WebMvcConfigurationSupport 会覆盖 Spring MVC 的默认配置，因此需要手动配置的内容可能会更多，需要开发者自行完成配置。
     * WebMvcConfigurer接口，更加灵活，能够保留默认配置，只需要覆盖需要修改的配置方法即可，避免了手动配置所有内容的繁琐。
     * 当需要更深层次、更细粒度的配置，并且能够熟悉和处理 Spring MVC 的全部配置细节时，使用继承 WebMvcConfigurationSupport类来进行配置。
     */
    private final JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
    private final JwtTokenUserInterceptor jwtTokenUserInterceptor;



    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenAdminInterceptor)
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/admin/employee/login");
        registry.addInterceptor(jwtTokenUserInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/user/login")
                .excludePathPatterns("/user/shop/status");
    }

    /**
     * 通过knife4j生成接口文档
     * @return
     * 2.在配置类中加入 knife4j 相关配置
     * .apis(RequestHandlerSelectors.basePackage("com.sky.controller"))：
     * 是指要扫描当前包下的所有的类和方法，
     * 就可以通过反射来解析这些类和方法，最终帮我们生成接口文档
     */
    @Bean
    public Docket docket1() {
        log.info("准备生成接口文档...");
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")
                .version("2.0")
                .description("苍穹外卖项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("sun")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
    @Bean
    public Docket docket2() {
        log.info("准备生成接口文档...");
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")
                .version("2.0")
                .description("苍穹外卖项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("用户端口")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    /**
     * 设置静态资源映射
     * @param registry
     * 3.设置静态资源映射，否则接口文档页面无法访问
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始设置静态资源映射...");
        // 通过ResourceHandlerRegistry对象配置了两个静态资源处理器，！！现在当我们浏览器访问localhost:8080/doc.html 的页面就是knife4j框架动态生成的
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 扩展Spring MVC框架的消息转换器，重写这个方法就行
     * 统一对返回前端的消息，做转换的处理，如日期类型的格式化
     * @param converters
     * 1.创建一个消息转换器对象  MappingJackson2HttpMessageConverter
     * 2.这个消息转换器需要指定一个对象转换器，这个自己创建一个  JacksonObjectMapper
     * 3.将消息对象转换器，加入到原始的Spring MVC消息对象转换器集合converters中，并指定索引位置靠前
     * 对象转换器，可以将我们这个java对象序列化为json数据
     * converters中存放的是整个mvc框架所使用的mvc消息转换器，是一个集合
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        // public void setObjectMapper(ObjectMapper objectMapper) {}
        converter.setObjectMapper(new JacksonObjectMapper());
        //这个容器里面其实已经自带了一些消息转换器，add之后呢，相当于自己的消息转换器排到了最后一个，其实排最后一个默认是使用不到的，要排到第一位
        converters.add(0,converter);
        
    }
}
